classdef AISStore
    
    
    properties
        secretkey = '';
        accesskey = '';
        baseurl = '';
        conn = '';
    end
 
    methods
        function S = AISStore(filename)
            % read the config file
            properties = java.util.Properties();
            properties.load(java.io.FileInputStream(filename));
            
            % get the access and secret keys
            S.secretkey = java.lang.String(properties.get('secretAccessKey'));
            S.accesskey = java.lang.String(properties.get('accessKey'));
            S.baseurl = strcat(properties.get('baseUrl'), properties.get('basePath.storage'));
            %S.baseurl = strcat('http://services.alma-in-silico.com', properties.get('basePath.storage'));
        end
        
        function s = getAsChar(S, bucket, objectkey)
            url = [S.baseurl, '/', bucket , '/', objectkey];
            jUrl = java.net.URL(url);
            java.lang.System.out.println(jUrl);
            S.conn = jUrl.openConnection();
            java.lang.System.out.println(S.conn);
            
            % set method
            S.conn.setRequestMethod('GET');
            
            % set all required headers
            contentType = java.lang.String('');
            contentMD5 = java.lang.String('');
            
            % add athorization and missing headers
            S.addAuthorization(contentType, contentMD5);
            java.lang.System.out.println(S.conn.getRequestProperty('authorization'));
            S.conn.connect();
            
            %s = S.conn.getRequestMethod();
            s = readstream(S.conn.getInputStream());
        end
        
        function getAsFile(S, bucket, objectkey, filename)
            import com.mathworks.mlwidgets.io.InterruptibleStreamCopier;
            url = [S.baseurl, '/', bucket , '/', objectkey];
            jUrl = java.net.URL(url);
            S.conn = jUrl.openConnection();
            
            % set method
            S.conn.setRequestMethod('GET');
            
            % set all required headers
            contentType = java.lang.String('');
            contentMD5 = java.lang.String('');
            
            % add athorization and missing headers
            S.addAuthorization(contentType, contentMD5);
            S.conn.connect();
            
            % pipe input stream into file seram
            in = S.conn.getInputStream();
            out = java.io.FileOutputStream(java.io.File(filename));
            isc = InterruptibleStreamCopier.getInterruptibleStreamCopier();
            isc.copyStream(in, out);
            in.close();
            out.close();
           
        end
        
        function putFile2(S, filename, bucket, objectKey)
            
        end
        
        function putFile(S, filename, bucket, objectkey)
            try
            fileInfo = dir(filename);
            fileSize = fileInfo.bytes;
            import com.mathworks.mlwidgets.io.InterruptibleStreamCopier;
            url = [S.baseurl, '/', bucket , '/', objectkey];
            jUrl = java.net.URL(url);
            java.lang.System.out.println(jUrl);
            S.conn = jUrl.openConnection();
            S.conn.setDoOutput(true);
            java.lang.System.out.println(S.conn);
            % set method
            S.conn.setRequestMethod('POST');
            S.conn.setRequestProperty('accept','application/json');
            %S.conn.setRequestProperty('content-length', fileSize);

            % set all required headers
            contentType = java.lang.String('application/octet-stream');
            contentMD5 = java.lang.String('');
%            S.conn.getCookieManager().clear('JSESSIONID');
            %S.conn.getCookieManager().elements.clear(java.lang.String('JSESSIONID'));
           
            S.conn.getCookieManager().removeAllCookies();
            S.conn.setFixedLengthStreamingMode(fileSize);
            
            % add athorization and missing headers
            S.addAuthorization(contentType, contentMD5);
            S.conn.connect();

            out = S.conn.getOutputStream();
            %out.flush();
            %out.close();
            
            in = java.io.FileInputStream(java.io.File(filename));
             % pipe input stream into file seram
            isc = InterruptibleStreamCopier.getInterruptibleStreamCopier();
            isc.copyStream(in, out);
            in.close();
            out.close();
            s = readstream(S.conn.getInputStream());
            java.lang.System.out.println(s);
             catch err
                java.lang.System.out.println(err.message);
                java.lang.System.err.println('put request failed...');
            end
        end
        
        
        
        
        function addAuthorization(S, contentType, contentMD5)
            %READSTREAM Read all bytes from stream to uint8
            try
                % first comput the date and set Date header
                dateFormat = 'EEE, dd MMM yyyy HH:mm:ss';
                format = java.text.SimpleDateFormat(dateFormat, java.util.Locale.US);
                format.setTimeZone(java.util.TimeZone.getTimeZone('GMT'));
                dat = format.format(java.util.Date());
                datestr = strcat(char(dat),' GMT');
                                java.lang.System.out.println('TAG2');
                
                S.conn.setRequestProperty('Date', datestr);
                
                % set the host header
                S.conn.setRequestProperty('host', S.conn.getURL().getHost());
                 java.lang.System.out.println(contentType);

                 java.lang.System.out.println(S.conn.getRequestProperty('host'));

                % set the eventual content-type header
                java.lang.System.out.println(contentType);
                if (~contentType.isempty())
                    S.conn.setRequestProperty('content-type', contentType);
                end
                java.lang.System.out.println('TAG2');

                % set the eventual content-type header
               if (~contentMD5.isempty())
                   S.conn.setRequestProperty('content-md5', contentMD5);
               end

                % compute the cannonical header for signature
                method = S.conn.getRequestMethod();
                
                buf = java.lang.StringBuilder();
                buf.append(method).append(sprintf('\n'));
                buf.append(contentMD5).append(sprintf('\n'));
                buf.append(contentType).append(sprintf('\n'));
                buf.append(datestr).append(sprintf('\n'));
                
                % do not consider other headers yet
                %final String headers = getHeaders(conn);
                %if (headers.length() > 0) {
                %	buf.append(headers);
                %}
                
                buf.append(S.conn.getURL().getPath());
                messageToSign = buf.toString();
                java.lang.System.out.println(messageToSign);
                % debug message to sign
                
                % now, sign...
                auth = java.lang.String();
                signingKey = javax.crypto.spec.SecretKeySpec(S.secretkey.getBytes(), 'HmacSHA1');
                mac = javax.crypto.Mac.getInstance('HmacSHA1');
                mac.init(signingKey);
                rawHmac = mac.doFinal(java.lang.String(messageToSign.getBytes(), 'UTF-8').getBytes());
                
                % base64-encode the hmac
                encoder = sun.misc.BASE64Encoder();
                signature = encoder.encode(rawHmac);
                java.lang.System.out.println(signature);
                
                S.conn.setRequestProperty('Authorization', ['AIS ',char(S.accesskey),':', char(signature)] );
                java.lang.System.out.println('AUTHORIZATION:');
                java.lang.System.out.println(S.conn.getRequestProperty('authorization'));
                %'
            catch err
                java.lang.System.out.println(err.message);
                java.lang.System.err.println('Authorization add failed');
            end
        end
        
        function out = readstream(inStream)
            %READSTREAM Read all bytes from stream to uint8
            try
                import com.mathworks.mlwidgets.io.InterruptibleStreamCopier;
                byteStream = java.io.ByteArrayOutputStream();
                isc = InterruptibleStreamCopier.getInterruptibleStreamCopier();
                isc.copyStream(inStream, byteStream);
                inStream.close();
                byteStream.close();
                out = native2unicode(typecast(byteStream.toByteArray', 'uint8')); %'
            catch err
                out = []; %HACK: quash
            end
            
        end
    end
end
